 
#ifndef __RSP_S_OBJLIST__HEADER_FILE__
#define __RSP_S_OBJLIST__HEADER_FILE__

#include "s_object.h"
#include "viewcont.h"

#include "coid/comm/hash/hashmap.h"
#include "coid/comm/binstream/circularstreambuf.h"

using namespace coid;


////////////////////////////////////////////////////////////////////////////////
///Object managing replicated objects
class rsp_s_objlist : public rsp_base
{
public:

    RSP_NO_FRAMECOMMAND

    void ref_ins( rsp_s_object_state* obj )
    {
        uint i = _vc.view_add(obj);

        if(!_incrupd) return;
        token t = obj->class_name();
        t.truncate(255);

        binstream& bin = _so->write_commands()
            << (uchar)OBJLIST_OP::OL_INS << (uchar)t.len();
        bin.xwrite_raw( t.ptr(), t.len() );
        bin << (ushort)i << (ushort)obj->oid();
    }

    void ref_del( uint oid )
    {
        uint i = _vc.view_del( oid, false );
        if( i == UMAX )  return;

        if(!_incrupd) return;
        _so->write_commands()
            << (uchar)OBJLIST_OP::OL_DEL << (ushort)i;
    }

    rsp_s_object_state* ref_find( uint oid ) const
    {
        return _vc.view_find(oid);
    }


    void set_owned_object( rsp_s_object_state* obj )
    {
        _owned = _vc.view_find_slot( obj->oid() );

        if(!_incrupd) return;
        _so->write_commands()
            << (uchar)OBJLIST_OP::OL_OWN << (ushort)_owned;
    }

    rsp_s_object_state* get_owned_object() const
    {
        if( _owned == UMAX )  return 0;
        return _vc.view_get(_owned);
    }


    RSP_CLASS_NAME("$",rsp_s_objlist)

    void stream_out( binstream& bin )
    {
        MARK_OUT('$');
        uints cnt = _vc._views.size();
        bin << (ushort)cnt;

        for( uints i=0; i<cnt; ++i ) {
            token t = _vc._views[i]->class_name();
            t.truncate(255);
            bin << (uchar)t.len();
            bin.xwrite_raw( t.ptr(), t.len() );
            bin << (ushort)_vc._views[i]->oid();
        }

        bin << (ushort)_owned;
        MARK_OUT('$'|0x80);
    }

    void stream_in( binstream& bin )
    {
    }

    bool diff( rsp_s_update& upd )
    {
        binstream& bin = *upd._bin;

        uint n = _vc._views.size();
        bin << (ushort)n;

        if( upd.full_update() )
            _mask.needc_new_bits( n, true );
        else
            _mask.need_new_bits(n);

        uint pm = (uint)bin.get_size();                   //remember global object bit mask pos.
        bin.xwrite_raw( _mask.ptr(), _mask.byte_size() ); //reserve mask

        int chng=0;
        if( upd.full_update() )
        {
            for( uint i=0; i<n; ++i )
            {
                if( !_vc._views[i] ) {
                    _mask.set_bit( i, 0 );
                    ++chng;
                }
                else {
                    //write skip/cnt
                    bin << (uchar)0x00 << (uchar)0x01;
                    //write size/fullupd
                    uint ps = (uint)bin.get_size();
                    bin << (ushort)0;

                    uint fsz = (uint)bin.get_size();
                    _vc._views[i]->stream_out(bin);

                    ushort sz = ushort( bin.get_size_pure(fsz) );
                    bin.overwrite_raw( ps, &sz, sizeof(ushort) );
                }
            }

            if(!chng)
                chng=-1;
        }
        else
        {
            for( uint i=0; i<n; ++i )
            {
                //writes diff mask and diff data for each rsp_s_object object
                if( _vc._views[i] && _vc._views[i]->write_diff(upd) )
                {
                    _mask.set_bit( i, 1 );
                    ++chng;
                }
                else
                    _mask.set_bit( i, 0 );
            }
        }

        //overwrite global object bit map on the beginning
        if(chng>0)
            bin.overwrite_raw( pm, _mask.ptr(), _mask.byte_size() );
        else if(!chng)
        {
            //rollback
            bin.set_size(pm-sizeof(ushort));
            bin << (ushort)0;
        }

        return chng!=0;
    }

    rsp_s_objlist()
    {
        reset();
    }

    void reset()
    {
        _vc.clear( false );

        _incrupd = 0;
        _owned = UMAX;
        _so = rsp_s_object_state::get_from_ptr(this);
        _so->reset();
        _vc.view_add( _so );
    }

    void set_incremental_mode()
    {
        _incrupd = 1;
    }

protected:

    dynarray<uchar> _mask;

    uint _owned;
    uint _incrupd;
    
    rsp_s_object_state* _so;
    rsp_ref_container<rsp_s_object_state> _vc;
};




#endif //__RSP_S_OBJLIST__HEADER_FILE__
